package cn.simon.free.ratelimiter.core.providers;

import cn.simon.free.ratelimiter.config.RedissonConfig;
import cn.simon.free.ratelimiter.core.Rate;
import cn.simon.free.ratelimiter.utils.AllMethodRateLimiterUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * redis 缓存(redisson分布式缓存)
 *
 * @author simon
 * @date 2020/3/25 10:44
 * @copyright:
 * @modifier
 * @motto a no talent, people who have to study hard
 */
@Slf4j
public class RedisCache implements CacheProviders {

    @Override
    public Object getValue(String key) {
        return RedisCacheUtils.get(key);
    }

    @Override
    public void putKey(String key, Object rate) {
        RedisCacheUtils.put(key, rate);
    }

    @Override
    public boolean checkAuthority(String key) {
        RBucket<Object> rBucket = (RBucket<Object>) RedisCacheUtils.get(key);
        if (!Objects.isNull(rBucket) && Objects.isNull(rBucket.get())) {
            Rate rate = AllMethodRateLimiterUtils.get(key);
            int decimalLength = judgeLength(rate.getRate());
            rBucket.set(rate.getRate() * Math.pow(10, decimalLength), (long) Math.pow(10, decimalLength), TimeUnit.SECONDS);
            return true;
        } else {
            if (rBucket.isExists() && rBucket.remainTimeToLive() != -2 && rBucket.remainTimeToLive() != -1) {
                double ticket = (double) rBucket.get();
                log.info("key:{},remain:{}", ticket, rBucket.remainTimeToLive());
                if (ticket > 0) {
                    rBucket.set(ticket - 1, rBucket.remainTimeToLive(), TimeUnit.MILLISECONDS);
                    return true;
                }
                return false;
            } else {
                return false;
            }
        }
    }

    private int judgeLength(double rate) {
        String v = String.valueOf(rate);
        int i = v.indexOf(".");
        String v1 = v.substring(i + 1);
        if ("00".equals(v1) || "0".equals(v1)) {
            return 0;
        } else {
            return v1.length();
        }
    }
}

/**
 * redis 工具类
 */
@Slf4j
class RedisCacheUtils {

    private RedisCacheUtils() {
    }

    /**
     * 取限流器
     *
     * @param key
     * @return
     */
    public static Object get(String key) {
        return RedissonConfig.getRedissonInstance().getBucket(key);
    }

    /**
     * 生成限流器
     *
     * @param key
     * @param rate
     */
    public static void put(String key, Object rate) {
        RBucket<Object> rMap = RedissonConfig.getRedissonInstance().getBucket(key);
        rMap.set(key);
        log.info("{}", rMap);
    }

}
